
from amscms import settings
from amscms.ams.forms import AdForm, AdvertizerForm
from amscms.ams.models import Ad, Advertizer, AdLikeDislike, AdTag, AdView, \
    AdStats, AdSearchHistory, AdOrder
from amscms.core.utils.captcha import validate_captcha
from amscms.core.utils.pagination import create_pagination_context
from amscms.core.utils.request import render_to_response
from amscms.core.views import index
from amscms.dict.models import Term
from amscms.payment.models import PaymentCredit, UserPaymentPolicy, \
    PaymentCreditHistory, CreditDepositHistory
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.utils import simplejson
from django.utils.translation import ugettext as _
from django.views.generic.list_detail import object_detail
from django.views.generic.simple import redirect_to
from django.utils.safestring import mark_safe
import datetime

"""
Displays a form and registers an instance of Ad
"""
@login_required()        
def ad_register(request):
    form = AdForm(request.user)
    context = {}
    if request.method == 'POST':
        form = AdForm(request.user, request.POST)
        if form.is_valid():
            ad, tags = Ad.objects.create_ad(form, request.user)
            # ad start date cannot be before today
            if ad.start_date <= datetime.date.today():
                context["error"] = _("Ad publish start date should at least be from tomorrow")
                context["form"] = form
                return render_to_response(request, 'ad/register.html', context)
            # ad start date should be before ad end date
            if ad.start_date >= ad.end_date:
                context["error"] = _("Ad start date should be at least prior to its end date")
                context["form"] = form
                return render_to_response(request, 'ad/register.html', context)
            cost, discount = Ad.objects.calculate_ad_cost(ad, request.user)
            context["object"] = ad
            context["tags"] = "   ".join(tags)
            context["cost"] = cost
            context["discount"] = discount
            context["RECAPTCHA_PUBLIC_KEY"] = settings.RECAPTCHA_PUBLIC_KEY
            request.session["registering_ad"] = ad
            request.session["registering_ad_tags"] = tags
            return render_to_response(request, 'ad/register_confirm.html', context)
        else:
            context["form"] = form
            return render_to_response(request, 'ad/register.html', context)
        return HttpResponseRedirect('/')
    if request.method == 'GET':
        context["form"] = form
        return render_to_response(request, 'ad/register.html', context)
    raise Http404

@login_required()
def ad_register_confirm(request):
    context = {}
    session = request.session
    if request.method == 'POST':
        if not session["registering_ad"]:
            return redirect_to(request, "/") 
        captcha_error = validate_captcha(request)
        if captcha_error is not None:
            context["error"] = _("Please enter the words in the following picture correctly")
            context["object"] = session["registering_ad"]
            context["tags"] = "   ".join(session["registering_ad_tags"])
            context["cost"], context["discount"] = Ad.objects.calculate_ad_cost(session["registering_ad"], request.user)
            context["RECAPTCHA_PUBLIC_KEY"] = settings.RECAPTCHA_PUBLIC_KEY
            return render_to_response(request, 'ad/register_confirm.html', context)
        else:
            ad = session["registering_ad"]
            tags = session["registering_ad_tags"]
            ad_order = Ad.objects.register_ad(ad, tags, request.user)
            if ad_order is None:
                request["ad_register_status"] = _("Registering the ad failed.")
                context["object"] = session["registering_ad"]
                context["tags"] = "   ".join(session["registering_ad_tags"])
                context["RECAPTCHA_PUBLIC_KEY"] = settings.RECAPTCHA_PUBLIC_KEY
                return render_to_response(request, 'ad/register_confirm.html', context)
            else:
                del session["registering_ad"]
                del session["registering_ad_tags"]
                return redirect_to(request, "/ads/orders/pay/%s/" % ad_order.id)
    if not request.method == 'POST' or not session["registering_ad"]: 
        return redirect_to(request, "/") 
    
@login_required()
def ad_list(request, page=1, extra=None):
    current_user = request.user
    object_list = Ad.objects.find_ads_by_user(current_user)
    pages, pc = create_pagination_context(object_list, '/my', page)
    if extra is not None:
        pc.update(extra)
    return render_to_response(request, 'ad/ad_list.html', pc)

@login_required()
def ad_reports(request, page=1):
    current_user = request.user
    object_list = Ad.objects.find_ads_by_user(current_user, "-stats__score")
    pages, pc = create_pagination_context(object_list, '/my/reports', page)
    return render_to_response(request, 'ad/ad_reports.html', pc)

@login_required()
def ad_delete(request, object_id):
    if not Ad.objects.owns(id, request.user):
        return redirect_to(request, "/")
    deposit = Ad.objects.delete_ad(object_id, request.user)
    context = {}
    if deposit is not None:
        context["message"] = _("Your credit has been updated for the ad update.")
    return ad_list(request, extra=context)

def ad_view(request, object_id, extra=None):
    user = request.user
    if user.is_anonymous() or not Ad.objects.owns(object_id, user): 
        if not Ad.objects.is_published(object_id):
            return redirect_to(request, "/")
    return ad_view_prepare(request, object_id, extra)

def ad_view_prepare(request, object_id, extra=None):
    qs = Ad.objects.all()
    likes = AdLikeDislike.objects.count_likes(object_id)
    dislikes = AdLikeDislike.objects.count_dislikes(object_id)
    adtags = AdTag.objects.find_adtags(object_id)
    count_views = AdView.objects.count_views(object_id)
    last_viewed = AdView.objects.find_last_viewed_time(object_id)
    other_ads = Ad.objects.find_other_ads_by_same_advertizer(object_id, 2)
    related_ads = Ad.objects.find_related_ads(object_id, 2)
    ec = {}
    if extra is not None:
        ec.update(extra)
    ec["likes"] = likes
    ec["dislikes"] = dislikes 
    ec["adtags"] = adtags
    ec["count_views"] = count_views
    ec["last_viewed"] = last_viewed
    ec["other_ads"] = other_ads
    ec["related_ads"] = related_ads
    return object_detail(request, object_id=object_id, queryset=qs, template_name="ad/ad_view.html", extra_context=ec)

@login_required()
def ad_update(request, object_id):
    context = {}
    if not Ad.objects.owns(object_id, request.user):
        return HttpResponseRedirect("/")
    ad = Ad.objects.get(pk=object_id)
    if request.method == 'GET':
        form = AdForm(request.user, instance=ad)
        context["form"] = form
        context["update"] = True
        context["object_id"] = object_id
        return render_to_response(request, 'ad/register.html', context)
    if request.method == 'POST':
        form = AdForm(request.user, request.POST, instance=ad)
        updated, adorder, deposit = Ad.objects.update_ad(object_id, form, request.user)
        if updated is None:
            context = {}
            context["form"] = form
            return render_to_response(request, 'ad/register.html', context)
        else:
            # we know that there is a payment or a deposit
            # maybe to pass some message to the user
            if adorder is not None:
                context["warning"] = mark_safe(_("You have a new ad order to be paid.") + \
                        "(<a href='%s'>%s</a>)" % ("/my/orders/", _("View")))
            if deposit is not None:
                context["warning"] = _("Your credit has been updated for the ad update.")
        return ad_view_prepare(request, object_id, context)

@login_required()
def ad_order_list(request, page=1):
    orders = AdOrder.objects.find_ad_orders(request.user)
    pages, pc = create_pagination_context(orders, '/my/orders', page)
    return render_to_response(request, 'ad/adorder_list.html', pc)

@login_required()
def ad_order_pay(request, id=None):
    if request.method == 'GET':
        if id is None:
            return None
        if not Ad.objects.owns(id, request.user):
            return redirect_to(request, "/")
        order = AdOrder.objects.get(pk=id)
        freepolicy = UserPaymentPolicy.objects.has_free_policy(request.user)
        if freepolicy:
            payable = True
        else:
            payable = PaymentCredit.objects.can_pay(request.user, order.amount)
        credit = PaymentCredit.objects.get_credit(request.user)
        return render_to_response(request, 'payment_confirm.html', 
                    {"payable" : payable, 
                     "freepolicy": freepolicy,
                     "credit": credit,
                     "order": order})
    if request.method == 'POST':
        id = request.POST["id"]
        if id is None:
            return None
        if not Ad.objects.owns(id, request.user):
            return redirect_to(request, "/")
        payment = PaymentCredit.objects.pay_order(request.user, id)
        if payment is None:
            return None 
        return redirect_to(request, "/my/")
    
@login_required()
def adorder_payment_list(request, page=1):
    current_user = request.user
    payments = PaymentCreditHistory.objects.find_payment_history(current_user)
    balance = PaymentCredit.objects.get_credit(current_user)
    pages, pc = create_pagination_context(payments, '/my/payments', page)
    pc["balance"] = balance
    return render_to_response(request, 'payment/payment_list.html', pc)

@login_required()
def credit_deposit_list(request, page=1):
    current_user = request.user
    deposits = CreditDepositHistory.objects.find_deposit_history(current_user)
    balance = PaymentCredit.objects.get_credit(current_user)
    pages, pc = create_pagination_context(deposits, '/my/deposits', page)
    pc["balance"] = balance
    return render_to_response(request, 'payment/deposit_list.html', pc)

@login_required()
def advertizer_register(request):
    form = AdvertizerForm()
    if request.method == 'POST':
        form = AdvertizerForm(request.POST)
        if form.is_valid():
            advertizer = form.save(commit=False)
            advertizer.user = request.user
            advertizer.save()
            return HttpResponseRedirect(request.POST['return'])
    redirect_url = '/my/'
    if request.GET.__contains__('return'):
        redirect_url = request.GET['return']
    return render_to_response(request, 'ad/advertizer/register.html', 
                              {'form' : form, 'redirect_url' : redirect_url})

@login_required()
def advertizer_list(request, page=1):
    current_user = request.user
    object_list = Advertizer.objects.find_advertizers_by_user(current_user)
    pages, pc = create_pagination_context(object_list, '/my/advertizers', page)
    return render_to_response(request, 'ad/advertizer/advertizer_list.html', pc)

def find_popular_tags(request):
    if request.method != 'GET':
        return HttpResponseRedirect('/')
    tags_dict = {}
    try:
        tags = Term.objects.find_popular_terms()
        for t in tags:
            tags_dict[t.term] = [t.id, t.frequency]
        return HttpResponse(simplejson.dumps(tags_dict, ensure_ascii=False), mimetype="application/json; charset=utf8")
    except Exception as e:
        return HttpResponse(simplejson.dumps({"error:" : e.__str__()}, ensure_ascii=False), mimetype="application/json; charset=utf8")
    
def explore_ads_by_tag(request, tagid, page=1):
    object_list = Ad.objects.find_ads_by_tag_id(tagid)
    if object_list is None:
        return index(request)
    pages, paging_context = create_pagination_context(object_list, "/ads/tag/explore/%s" % tagid, page)
    paging_context["tagid"] = tagid
    return render_to_response(request, 'ad/ad_explore.html', paging_context)

def explore_ads_by_advertizer(request, id, page=1):
    object_list = Ad.objects.find_ads_by_advertizer_id(id)
    pages, pc = create_pagination_context(object_list, '/ads/explore/advertizer/%s' % id, page)
    return render_to_response(request, 'ad/ad_explore.html', pc)

def search_ads_by_query(request, page=1):
    if request.method == 'POST':
        query = request.POST["query"]
        request.session["ad_query"] = query
    else:
        query = request.session["ad_query"]
    if query is None:
        return index(request)
    result = Ad.objects.find_ads(query)
    if result is None:
        return index(request)
    AdSearchHistory.objects.add_history(request.user, query)
    pages, paging_context = create_pagination_context(result, "/ads/search", page)
    return render_to_response(request, 'ad/ad_explore.html', paging_context)

def explore_ads_by_query(request, mode=None, page=1):
    if mode is None:
        ads = Ad.objects.find_top_ads(size=None)
        result = [ad['ad'] for ad in ads]
    else:
        if mode == 'views':
            ads = Ad.objects.find_top_ads(order_by="-stats__views", size=None)
            result = [ad['ad'] for ad in ads]
        elif mode == 'popular':
            ads = Ad.objects.find_top_ads(order_by="-stats__likes", size=None)
            result = [ad['ad'] for ad in ads]
        else:
            result = Ad.objects.find_latest_ads(mode)
    if result is None:
        return index(request)
    pages, paging_context = create_pagination_context(result, "/ads/explore", page)
    return render_to_response(request, 'ad/ad_explore.html', paging_context)

@login_required()
def ad_like(request, id):
    likes = AdLikeDislike.objects.count_likes(id)
    result = simplejson.dumps([likes], ensure_ascii=False)
    if request.method != 'GET':
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    if not request.is_ajax():
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    current_user = request.user
    if current_user.is_anonymous():
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    if AdLikeDislike.objects.user_scored_ad(current_user, id):
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    the_ad = Ad.objects.get(pk=id)
    adlike = AdLikeDislike(ad=the_ad, user=current_user, score=1)
    adlike.save()
    AdStats.objects.update_like_stats(id)
    likes = AdLikeDislike.objects.count_likes(id)
    result = simplejson.dumps([likes], ensure_ascii=False)
    return HttpResponse(result, mimetype="application/json; charset=utf8")

@login_required()
def ad_dislike(request, id):
    dislikes = AdLikeDislike.objects.count_dislikes(id)
    result = simplejson.dumps([dislikes], ensure_ascii=False)
    if request.method != 'GET':
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    if not request.is_ajax():
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    current_user = request.user
    if current_user.is_anonymous():
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    if AdLikeDislike.objects.user_scored_ad(current_user, id):
        return HttpResponse(result, mimetype="application/json; charset=utf8")
    the_ad = Ad.objects.get(pk=id)
    addislike = AdLikeDislike(ad=the_ad, user=current_user, score=-1)
    addislike.save()
    AdStats.objects.update_dislike_stats(id)
    dislikes = AdLikeDislike.objects.count_dislikes(id)
    result = simplejson.dumps([dislikes], ensure_ascii=False)
    return HttpResponse(result, mimetype="application/json; charset=utf8")

    
